﻿//using System;
//using System.Collections.Generic;
//using System.Text;
//using ZMQ;
//using System.Threading;
//using System.IO;

//namespace DCRF.Common.Distribution
//{
//    public class PeerManager : IDisposable
//    {
//        #region private fields

//        private PeerSocket gateway = null;
//        private string parentId = null;
//        private Dictionary<string, PeerSocket> peers = new Dictionary<string, PeerSocket>();

//        //key can be string (msgCode) or Guid (msgId)
//        //for handling a message sent from other initiator, we set handler for that msgCode
//        //for handling response sent from responder to us (initiator) we use msgId to receive response to 
//        //that exact message. For example if two exactly same messages are sent to a peer, their msgId will be different
//        //so each sender object instance will receive its own response
//        private Dictionary<object, MessageHandlerDelegate> handlers = new Dictionary<object, MessageHandlerDelegate>();

//        private int waitTimeout = 10000;

//        #endregion

//        #region public properties
//        public int PeerCount
//        {
//            get
//            {
//                refreshPeersStatus();

//                return this.peers.Count;
//            }
//        }
//        #endregion

//        #region public methods
//        public PeerManager(string _parentId)
//        {
//            parentId = _parentId;
//            gateway = new PeerSocket(parentId, null, this);

//            //there is no disconnect for a gateway
//            gateway.ResetHandler(PeerSocket.DisconnectMsgCode);

//            gateway.SetHandler(PeerSocket.ConnectMsgCode, new MessageHandlerDelegate(onConnect));

//            logEvent("Create PM("+parentId+") - Gateway Address = " + this.Address);
//        }

//        public bool HasPeer(string id)
//        {
//            return peers.ContainsKey(id);
//        }

//        public void Connect(string peerAddress, string peerId)
//        {
//            if (gateway == null) return;

//            refreshPeersStatus();

//            peers[peerId] = new PeerSocket(parentId, peerId, this);
//            peers[peerId].Connect(peerAddress);

//            logEvent("PM ("+parentId+") Connecting- PeerAddress = " + peerAddress+ " PeerId = " + peerId);

//            //inform the new peer about handlers
//            peers[peerId].SetHandler(PeerSocket.DefaultMsgCode, new MessageHandlerDelegate(internalDefaultHandler));
//        }

//        public void Disconnect()
//        {
//            string[] peerKeys = new string[peers.Count];

//            peers.Keys.CopyTo(peerKeys, 0);

//            foreach (string peer in peerKeys)
//            {
//                Disconnect(peer);
//            }
//        }

//        public void Disconnect(string peerId)
//        {
//            refreshPeersStatus();

//            if (gateway == null) return;
//            if (!peers.ContainsKey(peerId)) return;

//            logEvent("PM (" + Address + ") Disconnecting- PeerAddress = " + " PeerId = " + peerId);

//            peers[peerId].Disconnect();

//            peers.Remove(peerId);
//        }

//        public void Dispose()
//        {
//            refreshPeersStatus();

//            string[] keys = new string[peers.Count];
//            peers.Keys.CopyTo(keys, 0);

//            foreach (string key in keys)
//            {
//                Disconnect(key);
//            }

//            gateway.Dispose();
//            gateway = null;
//        }

//        public void dump()
//        {
//            refreshPeersStatus();

//            Console.WriteLine("dump for " + parentId);
//            foreach (string key in peers.Keys)
//            {
//                Console.WriteLine(key);
//            }
//            Console.WriteLine("----------------------------");
//            Console.WriteLine();
//        }

//        /// <summary>
//        /// when calling sendAsync, caller has to provide a handler if it requires the response
//        /// </summary>
//        /// <param name="msgCode"></param>
//        /// <param name="msgId"></param>
//        /// <param name="items"></param>
//        public void SendMessageAsync(string msgCode, MessageHandlerDelegate responseHandler, params object[] items)
//        {
//            SendMessageAsync(msgCode, responseHandler, new List<object>(items));
//        }

//        public void SendMessageAsync(string msgCode, MessageHandlerDelegate responseHandler, List<object> items)
//        {
//            sendMessageAsync(msgCode, Guid.NewGuid(), responseHandler, items);
//        }

//        /// <summary>
//        /// we cannot call sendMessageAsync(receiverId) because it will create 5 handlers for 5 receivers,
//        /// When container calls this method for multiple peers, it has set-up handler for a specific msgId
//        /// so we have to send messages using a pre-specified id
//        /// </summary>
//        /// <param name="msgCode"></param>
//        /// <param name="responseHandler"></param>
//        /// <param name="items"></param>
//        private void sendMessageAsync(string msgCode, Guid msgId, MessageHandlerDelegate responseHandler, List<object> items)
//        {
//            refreshPeersStatus();

//            //if caller requires the response, set it up and remove it after timeout of the call
//            if (responseHandler != null)
//            {
//                SetHandler(msgId, responseHandler);

//                //remove this handler after timeout so that the list of response handlers of this socket
//                //does not get full
//                //TODO: build a list of msgIds to remove and run a periodical code to remove them to 
//                //decrease load here in case of thousands of calls per second
//                ThreadPool.QueueUserWorkItem(new WaitCallback(
//                    delegate(object arg)
//                    {
//                        Thread.Sleep(this.waitTimeout);
//                        ResetHandler(msgId);
//                    }));
//            }

//            foreach (string key in peers.Keys)
//            {
//                peers[key].SendMessageAsync(msgCode, msgId, items);
//            }
//        }

//        public void SendMessageAsync(string receiverId, string msgCode, MessageHandlerDelegate responseHandler, params object[] items)
//        {
//            SendMessageAsync(receiverId, msgCode, responseHandler, new List<object>(items));
//        }

//        public void SendMessageAsync(string receiverId, string msgCode, MessageHandlerDelegate responseHandler, List<object> items)
//        {
//            refreshPeersStatus();
//            if (!peers.ContainsKey(receiverId)) return;

//            Guid msgId = Guid.NewGuid();

//            //if caller requires the response
//            if (responseHandler != null)
//            {
//                peers[receiverId].SetHandler(msgId, responseHandler);

//                //remove this handler after timeout so that the list of response handlers of this socket
//                //does not get full
//                //TODO: build a list of msgIds to remove and run a periodical handler to remove them to 
//                //decrease load here in case of thousands of calls per second
//                ThreadPool.QueueUserWorkItem(new WaitCallback(
//                    delegate(object arg)
//                    {
//                        Thread.Sleep(waitTimeout);

//                        if (peers.ContainsKey(receiverId))
//                        {
//                            PeerSocket socket = peers[receiverId];

//                            //maybe peer is disconnected when i was waiting
//                            if (socket != null)
//                            {
//                                socket.ResetHandler(msgId);
//                            }
//                        }
//                    }));
//            }

//            peers[receiverId].SendMessageAsync(msgCode, msgId, items);
//        }

//        /// <summary>
//        /// in this method, no msgId is required. Caller does not need to concern about id of its message.
//        /// PeerManager will handle to create and maintain id of the message and parse the result and 
//        /// finally return the result of the call.
//        /// </summary>
//        /// <param name="msgCode"></param>
//        /// <param name="items"></param>
//        /// <returns></returns>
//        public List<object> SendMessage(string msgCode, params object[] items)
//        {
//            return SendMessage(msgCode, new List<object>(items));
//        }

//        public List<object> SendMessage(string msgCode, List<object> items)
//        {
//            refreshPeersStatus();
//            if (peers.Count == 0) return null;

//            Guid msgId = Guid.NewGuid();
//            List<object> result = null;
//            ManualResetEvent waitHandle = new ManualResetEvent(false);

//            sendMessageAsync(msgCode, msgId, new MessageHandlerDelegate(
//                delegate(PeerSocket sender, string rmsgCode, Guid imsgId, string senderId, string receiverId, List<object> data)
//                {
//                    result = data;

//                    //add the id of the sender of the response at the end of result list
//                    result.Add(senderId);

//                    waitHandle.Set();
//                }), items);

//            waitHandle.WaitOne(waitTimeout);

//            //if no one has sent a response, data is inact and is null
//            return result;
//        }

//        //TODO: rename methods that send to all receivers to another name, at runtime this method is caleld when sending
//        //to all receivers
//        public List<object> SendMessage(string receiverId, string msgCode, params object[] items)
//        {
//            return SendMessage(receiverId, msgCode, new List<object>(items));
//        }

//        public List<object> SendMessage(string receiverId, string msgCode, List<object> items)
//        {
//            refreshPeersStatus();
//            if (!peers.ContainsKey(receiverId)) return null;

//            List<object> result = null;
//            ManualResetEvent waitHandle = new ManualResetEvent(false);

//            //no need to remove this temp handler, sendAsync will remove it automatically after 5 secs
//            SendMessageAsync(receiverId, msgCode, new MessageHandlerDelegate(
//                delegate(PeerSocket sender, string rmsgCode, Guid msgId, string senderId, string ireceiverId, List<object> data)
//                {
//                    result = data;

//                    //add the id of the sender of the response at the end of result list
//                    result.Add(senderId);

//                    waitHandle.Set();
//                }), items);

//            //wait for 5 secs to get the result
//            waitHandle.WaitOne(waitTimeout);

//            //if no one has sent a response, data is inact and is null
//            return result;
//        }

//        public void ResetHandler(object msgCodeOrId)
//        {
//            handlers.Remove(msgCodeOrId);
//        }

//        public void SetHandler(object msgCodeOrId, MessageHandlerDelegate handler)
//        {
//            handlers[msgCodeOrId] = handler;
//        }

//        public string Address
//        {
//            get
//            {
//                refreshPeersStatus();

//                return gateway.Address;
//            }
//        }

//        #endregion

//        #region private methods

//        private void onConnect(PeerSocket sender, string msgCode, Guid msgId, string senderId, string receiverId, List<object> data)
//        {
//            //read the other-side address
//            string otherAddress = (string)data[0];

//            logEvent("PM (" + this.parentId + ") - Receive Connect Request - PeerAddress = " + otherAddress + ", PeerId = " + senderId);

//            peers[senderId] = new PeerSocket(parentId, senderId, this);
//            peers[senderId].Connect(otherAddress);

//            //inform the new peer about handlers
//            peers[senderId].SetHandler(PeerSocket.DefaultMsgCode, new MessageHandlerDelegate(internalDefaultHandler));
//        }

//        private void internalDefaultHandler(PeerSocket sender, string msgCode, Guid msgId, string senderId, string receiverId, List<object> data)
//        {
//            //check top-level handlers which are to be executed for all sockets
//            //priority of message-id is higher than msgCode
//            if (handlers.ContainsKey(msgId))
//            {
//                handlers[msgId](sender, msgCode, msgId, senderId, receiverId, data);
//            }
//            else if (handlers.ContainsKey(msgCode))
//            {
//                handlers[msgCode](sender, msgCode, msgId, senderId, receiverId, data);
//            }

//        }

//        private void refreshPeersStatus()
//        {
//            List<string> toDelete = new List<string>();

//            foreach (string key in peers.Keys)
//            {
//                if (peers[key].IsDisposed)
//                {
//                    toDelete.Add(key);
//                }
//            }

//            foreach (string key in toDelete)
//            {
//                peers.Remove(key);
//            }
//        }

//        #endregion

//        private void logEvent(string log)
//        {
//            StreamWriter sw = new StreamWriter("C:\\peerSocket.log", true);
//            sw.WriteLine(log);
//            sw.Close();
//        }
//    }
//}
